﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Aleator.Core;
using Aleator.Core.Techniques;
using System.Threading;

namespace Aleator.Helpers
{
    /// <summary>
    /// Arragement enum
    /// </summary>
    public enum Arrangement
    {
        Drums,
        Lead,
        DrumsBass,
        DrumsLead,
        LeadRhythm,
        NoDrums,
        NoBass
    }

    /// <summary>
    /// Singleton class for handling variable instrumentation
    /// </summary>
    public static class Instrumentation
    {
        /// <summary>
        /// Determing the instrumentation for this phrase
        /// </summary>
        /// <param name="phrase"></param>
        public static void Arrange(ConcreteProgression progression)
        {
            int a_type;
            string section = "";
            List<string> typelist = null;

            if (progression.ProgressionID == 0)
            {
                section = "intro";

                //20% chance on intro
                if (Session.RndGenerator.Next(10) > 7)
                {
                    //Everything but lead rhythm
                    typelist = Enum.GetValues(typeof(Arrangement)).Cast<Arrangement>().Where(a => (int)a != 5).Select(a => a.ToString()).ToList();
                }
            }
            else if (progression.ProgressionID == progression.Composition.Progressions.OrderByDescending(p => p.ProgressionID).Select(p => p.ProgressionID).First())
            {
                section = "outro";

                //20% chance on outro
                if (Session.RndGenerator.Next(10) > 7)
                {
                    //Lead, DrumsLead, LeadRhythm, NoDrums
                    int[] typearray = { 2, 4, 5, 6 };
                    typelist = Enum.GetValues(typeof(Arrangement)).Cast<Arrangement>().Where(a => Array.IndexOf(typearray, (int)a) > -1).Select(a => a.ToString()).ToList();
                }
            }
            else if (progression.Composition.Progressions.Count > 4)
            {
                section = "break";

                int break_min = progression.Composition.Progressions.OrderBy(p => p.ProgressionID).Select(p => p.ProgressionID).First() + 2;
                int break_max = progression.Composition.Progressions.OrderByDescending(p => p.ProgressionID).Select(p => p.ProgressionID).First() - 2;

                if ((break_min <= progression.ProgressionID && progression.ProgressionID <= break_max) && Session.RndGenerator.Next(10) > 8)
                {
                    //Drums, DrumsBass, DrumsLead, NoBass
                    int[] typearray = { 1, 3, 4, 7 };
                    typelist = Enum.GetValues(typeof(Arrangement)).Cast<Arrangement>().Where(a => Array.IndexOf(typearray, (int)a) > -1).Select(a => a.ToString()).ToList();
                }
            }
            else
                return;

            a_type = Session.RndGenerator.Next(typelist.Count);

            typeof(Instrumentation).GetMethod(typelist.ElementAt(a_type), System.Reflection.BindingFlags.NonPublic).Invoke(null, new object[] { progression, section });

        }

        private static void Drums(ConcreteProgression p, string section)
        {
            int omitted = 3;

            if (section == "intro")
            {
                omitted = Session.RndGenerator.Next(1,3) * 2;
            }
            else
            {
                while (omitted == 3)
                    omitted = Session.RndGenerator.Next(1,5);
            }
        }


        private static void Lead(ConcreteProgression p, string section)
        {
            int omitted = Session.RndGenerator.Next(1, 4) * 2;

            if (section == "intro")
            {

            }
            else
            {

            }
        }


        private static void DrumsBass(ConcreteProgression p, string section)
        {
            int omitted = Session.RndGenerator.Next(1, 4) * 2;

            if (section == "intro")
            {

            }
            else
            {

            }
        }


        private static void DrumsLead(ConcreteProgression p, string section)
        {
            int omitted = 3;

            if (section == "intro")
            {
                omitted = Session.RndGenerator.Next(1, 4) * 2;
            }
            else if (section == "break")
            {
                while (omitted == 3)
                    omitted = Session.RndGenerator.Next(1, 5);
            }
            else
            {
                omitted = Session.RndGenerator.Next(1, 4) * 2;
            }
        }


        private static void LeadRhythm(ConcreteProgression p, string section)
        {
            int omitted = 3;

            if (section == "intro")
            {
                omitted = Session.RndGenerator.Next(1, 4) * 2;
            }
            else if (section == "break")
            {
                while (omitted == 3)
                    omitted = Session.RndGenerator.Next(1, 5);
            }
            else
            {
                omitted = Session.RndGenerator.Next(1, 4) * 2;
            }
        }


        private static void NoDrums(ConcreteProgression p, string section)
        {
            int omitted = Session.RndGenerator.Next(1, 3) * 2;
        }


        private static void NoBass(ConcreteProgression p, string section)
        {
            int omitted = 3;

            if (section == "intro")
            {
                omitted = Session.RndGenerator.Next(1, 4) * 2;
            }
            else if (section == "break")
            {
                while (omitted == 3)
                    omitted = Session.RndGenerator.Next(1, 5);
            }
            else
            {
                omitted = Session.RndGenerator.Next(1, 4) * 2;
            }
        }


        private static void Add()
        {
            //Use this for crashes, utilities, additional arps etc
            throw new Exception("No implementation!");
        }
    }
}
